package com.zd.lib.http.okhttp;

import android.support.annotation.Nullable;
import android.util.Log;


import com.zd.lib.http.cache.Cache;
import com.zd.lib.http.cache.DiskBasedCache;

import java.io.File;
import java.io.IOException;
import java.net.ConnectException;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
import java.nio.charset.Charset;
import java.util.List;

import okhttp3.FormBody;
import okhttp3.Interceptor;
import okhttp3.Protocol;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import okhttp3.ResponseBody;

/**
 * Created by zoudong on 16/8/18.
 * 缓存 http  信息   post 请求 无网络情况下 读取网络
 *  一般来说  POST 请求是不缓存数据的，   这个只要用于Post 缓存数据
 *  使用方法    Retrofit
 *  使用  @Headers({"isCache :true"}, {"expiredTime:60*60"})
 *  @version 1.2  fix Post无数据缓存问题
 *  @version 1.3  添加 网络不用情况下 读取缓存
 */
public class PostNoNetWorkCacheInterceptor implements Interceptor {
    private static final Charset UTF8 = Charset.forName("UTF-8");
    private static Cache mCache;
    private final long EXPIREDDEFTIME =60*60*24*7;  //一周时间缓存
    public PostNoNetWorkCacheInterceptor(File tempFile, int size) {
        if (mCache == null) {
              mCache = new DiskBasedCache(tempFile,size);
             mCache.initialize();
        }
    }

    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
          long expiredtime = 0; //缓存的时间  默认 一周时间
                if (request.method().equals("POST") && (expiredtime=isCache(request))>0){//设置isCache =true
//                    if (NetworkUtils.isNetworkAvailable(AppContextApplication.getInstance())) { //有网情况下
                        Response response=null;
                        try {
                             response = chain.proceed(request);  //网络请求
                        } catch ( IOException e) {
                            //网络请求失败， 超时，连接失败
                            if (e instanceof SocketTimeoutException || e instanceof UnknownHostException || e instanceof ConnectException) {
                                Response fromCache = readCache(request);
                                if (fromCache != null) return fromCache;
                                if (e instanceof SocketTimeoutException ) {
                                    throw new SocketTimeoutException(e.getMessage());  //没有获取到缓存 直接throw IOException
                                }
                                if (e instanceof UnknownHostException ) {
                                    throw new UnknownHostException(e.getMessage());  //没有获取到缓存 直接throw IOException
                                }
                                if (e instanceof ConnectException ) {
                                    throw new ConnectException(e.getMessage());  //没有获取到缓存 直接throw IOException
                                }

                                throw new IOException(e.getMessage(),e.getCause());  //没有获取到缓存 直接throw IOException
                            }
                            throw new IOException(e.getMessage(),e.getCause());  //没有获取到缓存 直接throw IOException
                        }
                        executeCache(request, expiredtime, response);//保存网络
                        return response;
                    } /*else { //无网络情况下
                            Response fromCache = readCache(request);
                        if (fromCache != null) return fromCache;
                    }
//            }*/
        return chain.proceed(request);
    }

    /**
     * 读取缓存
     * @param request
     * @return
     * @throws IOException
     */
    @Nullable
    private Response readCache(Request request) throws IOException {
        if (mCache != null) {
            Cache.Entry fromCache = mCache.get(getRequestKey(request));
            if (fromCache != null&&!fromCache.isExpired()) {//    缓存命中且 时间未过期
                return new Response.Builder().request(request).protocol(Protocol.HTTP_1_1).code(200).body(ResponseBody.create(request.body().contentType(), fromCache.data)).build();
            }
        }
        return null;
    }

    private void executeCache(Request request, long expiredtime, Response response) {
        try {
            //-----------------
            mCache.put(getRequestKey(request), mCache.responseToEntry(response.body(), expiredtime));
            //---------
//                            ResponseBody responseBody = response.body();
//                            byte[] content = response.body().bytes(); //网络数据
//                            mCache.put(getRequestKey(request), mCache.responseToEntry(content, expiredtime)); //缓存数据
//                            // 这里不能 直接返回response  因为调用了 response.body.bytes()  已经掉用流的close()
//                            ResponseBody responseBody = ResponseBody.create(response.body().contentType(), content);
//                            return response.newBuilder().body(responseBody).build();
        } catch (IOException e) {
            Log.i("cache",e.toString());
        }
    }

    /**
     * 缓存的key
     * @param request
     * @return
     */
    private String getRequestKey(Request request) throws IOException {
        RequestBody body1 = request.body();
        if (body1.contentLength() > 0 && body1.contentType() != null&&body1 instanceof FormBody) { //判断是否Post带数据
            FormBody body = (FormBody) body1;
            int size = body.size();
            if (size == 0) {
                return request.url().toString();
            }
            StringBuilder builder = new StringBuilder();
            for (int i = 0; i < size; i++) {
                builder.append(body.name(i) + "=" + body.value(i)).append("&");
            }
            return request.url().toString()+"?"+builder.substring(0, builder.length() - 1);
        }
       return  request.url().toString();
    }

    /**
     * 判断是否 需要缓存
     * @param request
     * @return
     */
    private  long isCache(Request request){
        List<String> isCache = request.headers("isCache");
        List<String> expiredTime = request.headers("expiredTime");
        //判断是不是isCache
        if (isCache!=null&&isCache.size()>0&&"true".equals(isCache.get(isCache.size()-1))) {
            String expired = null;
            if (expiredTime != null && expiredTime.size() > 0) {
                expired = expiredTime.get(expiredTime.size() - 1);
            }
             return Long.getLong(expired, EXPIREDDEFTIME);
        }
          return  0;
    }

}
